* convert ozi io to QTextStream.
and add an option to set the codec.
default the codec to windows-1252, which matches historic
usage but not recent behavior.
fix a memory leak, csv_lineparse needs to die.
fix a mistranslation with QString::arg.
* enhance ozi test for routes and tracks.
* eliminate csv_lineparse in ozi.
* eliminate obsolete commented code in ozi.
* update encoding comments for ozi.
* add doc for ozi codec option.
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+ Reference:
+ https://www.oziexplorer4.com/eng/help/fileformats.html
+
+ According to the OZI Explorer developer:
+ "There is no specified character set, it defaults to whatever 8 bit
+ character set "Windows" defaults to - normally CP-1252 but can vary
+ depending on Windows regional settings."
+
+ According to the reference, for some text fields:
+ "comma's not allowed in text fields, character 209 can be used instead
+ and a comma will be substituted."
+ This could work for windows-1252, but not for utf-8.
+ We don't support any special handling for character 209.
+
*/
+#include <cctype> // for tolower
+#include <cmath> // for lround
+#include <cstdlib> // for atoi
+
+#include <QtCore/QByteArray> // for QByteArray
+#include <QtCore/QChar> // for operator==, QChar
+#include <QtCore/QCharRef> // for QCharRef
+#include <QtCore/QFile> // for QFile
+#include <QtCore/QFileInfo> // for QFileInfo
+#include <QtCore/QFlags> // for QFlags
+#include <QtCore/QIODevice> // for operator|, QIODevice::WriteOnly, QIODevice::ReadOnly, QIODevice, QIODevice::OpenModeFlag
+#include <QtCore/QString> // for QString
+#include <QtCore/QStringList> // for QStringList
+#include <QtCore/QTextCodec> // for QTextCodec
+#include <QtCore/QTextStream> // for QTextStream, operator<<, qSetRealNumberPrecision, QTextStream::FixedNotation
+#include <QtCore/Qt> // for CaseInsensitive
+#include <QtCore/QtGlobal> // for qPrintable
+
#include "defs.h"
-#include "cet_util.h"
-#include "csv_util.h"
-#include "jeeps/gpsmath.h"
-#include <QtCore/QFileInfo>
-#include <cctype>
-#include <cmath> /* for floor */
-#include <cstdio>
-#include <cstdlib>
+#include "csv_util.h" // for csv_stringclean
+#include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_WGS84_M
+#include "src/core/datetime.h" // for DateTime
+#include "src/core/file.h" // for File
+
#define MYNAME "OZI"
#define BADCHARS ",\r\n"
#define DAYS_SINCE_1990 25569
-typedef struct {
+struct ozi_fsdata {
format_specific_data fs;
int fgcolor;
int bgcolor;
-} ozi_fsdata;
+};
+static struct {
+ gpsbabel::File* file{nullptr};
+ QTextStream* stream{nullptr};
+ QTextCodec* codec{nullptr};
+} ozi_file;
-static gbfile* file_in, *file_out;
static short_handle mkshort_handle;
static route_head* trk_head;
static route_head* rte_head;
static char proxunit;
static double alt_scale;
static double prox_scale;
+static char* opt_codec;
static
arglist_t ozi_args[] = {
"proxunit", &proxunit_opt, "Unit used in proximity values",
"miles", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
},
+ {
+ "codec", &opt_codec, "codec to use for reading and writing strings (default windows-1252)",
+ "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ },
ARG_TERMINATOR
};
static QString ozi_ofname;
+static void
+ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode)
+{
+ ozi_file.codec = QTextCodec::codecForName(opt_codec);
+ if (ozi_file.codec == nullptr) {
+ fatal(MYNAME ": Unsupported character set '%s'.\n", opt_codec);
+ }
+
+ ozi_file.file = new gpsbabel::File(fname);
+ ozi_file.file->open(mode);
+ ozi_file.stream = new QTextStream(ozi_file.file);
+ ozi_file.stream->setCodec(ozi_file.codec);
+
+ if (mode | QFile::WriteOnly) {
+ ozi_file.stream->setRealNumberNotation(QTextStream::FixedNotation);
+ }
+
+ if (mode | QFile::ReadOnly) {
+ if (ozi_file.codec->mibEnum() == 106) { // UTF-8
+ ozi_file.stream->setAutoDetectUnicode(true);
+ }
+ }
+}
+
+static void
+ozi_close_io()
+{
+ ozi_file.file->close();
+ delete ozi_file.file;
+ ozi_file.file = nullptr;
+ delete ozi_file.stream;
+ ozi_file.stream = nullptr;
+ ozi_file.codec = nullptr;
+}
+
static void
ozi_copy_fsdata(ozi_fsdata** dest, ozi_fsdata* src)
{
return fsdata;
}
-static void
-ozi_get_time_str(const Waypoint* waypointp, char* buff, gbsize_t buffsz)
+static QString
+ozi_get_time_str(const Waypoint* waypointp)
{
if (waypointp->creation_time.isValid()) {
double time = (waypt_time(waypointp) / SECONDS_PER_DAY) + DAYS_SINCE_1990;
- snprintf(buff, buffsz, "%.7f", time);
- } else {
- *buff = '\0';
+ return QString("%1").arg(time, 0, 'f', 7);
}
+ return QString("");
}
static void
*/
if (fname == "-") {
- if (! file_out) {
- file_out = gbfopen(fname, "wb", MYNAME);
+ if (ozi_file.file == nullptr) {
+ ozi_open_io(fname, QFile::WriteOnly);
}
return;
}
QString buff;
if ((track_out_count) && (ozi_objective == trkdata)) {
- buff = QString("-%d").arg(track_out_count);
+ buff = QString("-%1").arg(track_out_count);
} else {
buff = QString("");
}
QString tmpname = QString("%1%2.%3").arg(sname, buff, ozi_extensions[ozi_objective]);
/* re-open file_out with the new filename */
- if (file_out) {
- gbfclose(file_out);
- file_out = nullptr;
+ if (ozi_file.file != nullptr) {
+ ozi_close_io();
}
-
- file_out = gbfopen(tmpname, "wb", MYNAME);
+
+ ozi_open_io(tmpname, QFile::WriteOnly);
}
static void
ozi_track_hdr(const route_head* rte)
{
- static const char* ozi_trk_header =
- "OziExplorer Track Point File Version 2.1\r\n"
- "WGS 84\r\n"
- "Altitude is in %s\r\n"
- "Reserved 3\r\n"
- "0,2,255,%s,0,0,2,8421376\r\n"
- "0\r\n";
-
if ((! pack_opt) || (track_out_count == 0)) {
ozi_openfile(ozi_ofname);
- gbfprintf(file_out, ozi_trk_header,
- altunit == 'f' ? "Feet" : "Meters",
- rte->rte_name.isEmpty() ? "ComplimentsOfGPSBabel" : CSTRc(rte->rte_name));
+ *ozi_file.stream << "OziExplorer Track Point File Version 2.1\r\n"
+ << "WGS 84\r\n"
+ << "Altitude is in " << (altunit == 'f' ? "Feet" : "Meters") << "\r\n"
+ << "Reserved 3\r\n"
+ << "0,2,255,"
+ << (rte->rte_name.isEmpty() ? "ComplimentsOfGPSBabel" : rte->rte_name)
+ << ",0,0,2,8421376\r\n"
+ << "0\r\n";
}
track_out_count++;
ozi_track_disp(const Waypoint* waypointp)
{
double alt;
- char ozi_time[16];
- ozi_get_time_str(waypointp, ozi_time, sizeof(ozi_time));
+ QString ozi_time = ozi_get_time_str(waypointp);
if (waypointp->altitude == unknown_alt) {
alt = -777;
alt = waypointp->altitude * alt_scale;
}
- gbfprintf(file_out, "%.6f,%.6f,%d,%.0f,%s,,\r\n",
- waypointp->latitude, waypointp->longitude, new_track,
- alt, ozi_time);
+ *ozi_file.stream << qSetRealNumberPrecision(6) << waypointp->latitude << ','
+ << waypointp->longitude << ','
+ << new_track << ','
+ << qSetRealNumberPrecision(0) << alt << ','
+ << ozi_time << ",,\r\n";
new_track = 0;
}
-static void
-ozi_track_tlr(const route_head*)
-{
-}
-
static void
ozi_track_pr()
{
- track_disp_all(ozi_track_hdr, ozi_track_tlr, ozi_track_disp);
+ track_disp_all(ozi_track_hdr, nullptr, ozi_track_disp);
}
static void
{
/* prologue on 1st pass only */
if (route_out_count == 0) {
- static const char* ozi_route_header =
- "OziExplorer Route File Version 1.0\r\n"
- "WGS 84\r\n"
- "Reserved 1\r\n"
- "Reserved 2\r\n";
- gbfprintf(file_out, ozi_route_header);
+ *ozi_file.stream << "OziExplorer Route File Version 1.0\r\n"
+ << "WGS 84\r\n"
+ << "Reserved 1\r\n"
+ << "Reserved 2\r\n";
}
route_out_count++;
* R, 1, ICP GALHETA,, 16711680
*/
- gbfprintf(file_out, "R,%d,%s,%s,\r\n",
- route_out_count,
- CSTRc(rte->rte_name),
- CSTRc(rte->rte_desc));
+ *ozi_file.stream << "R," << route_out_count << ','
+ << rte->rte_name << ','
+ << rte->rte_desc << ",\r\n";
}
static void
ozi_route_disp(const Waypoint* waypointp)
{
- char ozi_time[16];
-
route_wpt_count++;
- ozi_get_time_str(waypointp, ozi_time, sizeof(ozi_time));
+ QString ozi_time = ozi_get_time_str(waypointp);
/*
double alt;
* W,1,7,7,007,-25.581670,-48.316660,36564.54196,10,1,4,0,65535,TR ILHA GALHETA,0,0
*/
- gbfprintf(file_out, "W,%d,,%d,%s,%.6f,%.6f,%s,0,1,3,0,65535,%s,0,0\r\n",
- route_out_count,
- route_wpt_count,
- CSTR(waypointp->shortname),
- waypointp->latitude,
- waypointp->longitude,
- ozi_time,
- CSTR(waypointp->description));
+ *ozi_file.stream << "W," << route_out_count << ",,"
+ << route_wpt_count << ','
+ << waypointp->shortname << ','
+ << qSetRealNumberPrecision(6) << waypointp->latitude << ','
+ << waypointp->longitude << ','
+ << ozi_time << ",0,1,3,0,65535,"
+ << waypointp->description << ",0,0\r\n";
}
-static void
-ozi_route_tlr(const route_head*)
-{
-}
-
static void
ozi_route_pr()
{
- route_disp_all(ozi_route_hdr, ozi_route_tlr, ozi_route_disp);
+ route_disp_all(ozi_route_hdr, nullptr, ozi_route_disp);
}
static void
static void
rd_init(const QString& fname)
{
- file_in = gbfopen(fname, "rb", MYNAME);
+ ozi_open_io(fname, QFile::ReadOnly);
mkshort_handle = mkshort_new_handle();
ozi_init_units(0);
static void
rd_deinit()
{
- gbfclose(file_in);
- file_in = nullptr;
+ ozi_close_io();
+
mkshort_del_handle(&mkshort_handle);
}
ozi_init_units(1);
parse_distance(proximityarg, &proximity, 1 / prox_scale, MYNAME);
-
- file_out = nullptr;
}
static void
wr_deinit()
{
- if (file_out != nullptr) {
-
- gbfclose(file_out);
- file_out = nullptr;
- }
+ ozi_close_io();
ozi_ofname.clear();
mkshort_del_handle(&mkshort_handle);
}
static void
-ozi_parse_track(int field, char* str, Waypoint* wpt_tmp, char* trk_name)
+ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name)
{
- double alt;
-
- if (*str == '\0') {
+ if (str.isEmpty()) {
return;
}
switch (field) {
case 0:
/* latitude */
- wpt_tmp->latitude = atof(str);
+ wpt_tmp->latitude = str.toDouble();
break;
case 1:
/* longitude */
- wpt_tmp->longitude = atof(str);
+ wpt_tmp->longitude = str.toDouble();
break;
case 2:
/* new track flag */
- if ((atoi(str) == 1) && (trk_head->rte_waypt_ct > 0)) {
+ if ((str.toInt() == 1) && (trk_head->rte_waypt_ct > 0)) {
trk_head = route_head_alloc();
track_add_head(trk_head);
if (trk_name) {
}
}
break;
- case 3:
+ case 3: {
/* altitude */
- alt = atof(str);
+ double alt = str.toDouble();
if (alt == -777) {
wpt_tmp->altitude = unknown_alt;
} else {
wpt_tmp->altitude = alt * alt_scale;
}
break;
+ }
case 4:
/* DAYS since 1900 00:00:00 in days.days (5.5) */
ozi_set_time_str(str, wpt_tmp);
}
static void
-ozi_parse_routepoint(int field, char* str, Waypoint* wpt_tmp)
+ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp)
{
- if (*str == '\0') {
+ if (str.isEmpty()) {
return;
}
break;
case 5:
/* latitude */
- wpt_tmp->latitude = atof(str);
+ wpt_tmp->latitude = str.toDouble();
break;
case 6:
/* longitude */
- wpt_tmp->longitude = atof(str);
+ wpt_tmp->longitude = str.toDouble();
break;
case 7:
/* DAYS since 1900 00:00:00 in days.days (5.5) */
}
static void
-ozi_parse_routeheader(int field, const QString& str, Waypoint*)
+ozi_parse_routeheader(int field, const QString& str)
{
switch (field) {
char* trk_name = nullptr;
int linecount = 0;
- while ((buff = gbfgetstr(file_in)), !buff.isNull()) {
- if ((linecount++ == 0) && file_in->unicode) {
- cet_convert_init(CET_CHARSET_UTF8, 1);
+ while (true) {
+ buff = ozi_file.stream->readLine();
+ if (buff.isNull()) {
+ break;
}
+ linecount++;
/*
* this is particularly nasty. use the first line of the file
}
}
} else if ((linecount == 5) && (ozi_objective == trkdata)) {
- int field = 0;
- char* s = csv_lineparse(CSTR(buff), ",", "", linecount);
- while (s) {
- field ++;
- if (field == 4) {
- trk_head->rte_name = QString(s).trimmed();
- }
- s = csv_lineparse(nullptr, ",", "", linecount);
+ const QStringList parts = buff.split(',');
+ if (parts.size() >= 4) {
+ trk_head->rte_name = parts.at(3).trimmed();
}
}
ozi_fsdata* fsdata = ozi_alloc_fsdata();
Waypoint* wpt_tmp = new Waypoint;
- /* data delimited by commas, possibly enclosed in quotes. */
- char* orig_s = xstrdup(CSTR(buff));
- char* s = csv_lineparse(orig_s, ",", "", linecount);
+ /* data delimited by commas. */
+ const QStringList parts = buff.split(',');
int i = 0;
bool header = false;
- while (s) {
+ for (const auto& s : parts) {
switch (ozi_objective) {
case trkdata:
ozi_parse_track(i, s, wpt_tmp, trk_name);
break;
case rtedata:
if (buff[0] == 'R') {
- ozi_parse_routeheader(i, QString(s), wpt_tmp);
+ ozi_parse_routeheader(i, QString(s));
header = true;
} else {
ozi_parse_routepoint(i, s, wpt_tmp);
break;
}
i++;
- s = csv_lineparse(nullptr, ",", "", linecount);
}
- xfree(orig_s);
switch (ozi_objective) {
case trkdata:
{
static int index = 0;
double alt;
- char ozi_time[16];
QString description;
QString shortname;
int faked_fsdata = 0;
faked_fsdata = 1;
}
- ozi_get_time_str(wpt, ozi_time, sizeof(ozi_time));
+ QString ozi_time = ozi_get_time_str(wpt);
if (wpt->altitude == unknown_alt) {
alt = -777;
icon = wpt->icon_descr.toInt();
}
- gbfprintf(file_out,
- "%d,%s,%.6f,%.6f,%s,%d,%d,%d,%d,%d,%s,%d,%d,",
- index, CSTRc(shortname), wpt->latitude, wpt->longitude, ozi_time, icon,
- 1, 3, fs->fgcolor, fs->bgcolor, CSTRc(description), 0, 0);
+ *ozi_file.stream << index << ','
+ << shortname << ','
+ << qSetRealNumberPrecision(6) << wpt->latitude << ','
+ << wpt->longitude << ','
+ << ozi_time << ','
+ << icon << ','
+ << "1,3,"
+ << fs->fgcolor << ','
+ << fs->bgcolor << ','
+ << description << ",0,0,";
if (WAYPT_HAS(wpt, proximity) && (wpt->proximity > 0)) {
- gbfprintf(file_out, "%.1f,", wpt->proximity * prox_scale);
+ *ozi_file.stream << qSetRealNumberPrecision(1) << wpt->proximity * prox_scale << ',';
} else if (proximity > 0) {
- gbfprintf(file_out,"%.1f,", proximity * prox_scale);
+ *ozi_file.stream << qSetRealNumberPrecision(1) << proximity * prox_scale << ',';
} else {
- gbfprintf(file_out,"%d,", 0);
+ *ozi_file.stream << "0,";
}
- gbfprintf(file_out, "%.0f,%d,%d,%d\r\n", alt, 6, 0, 17);
+ *ozi_file.stream << qSetRealNumberPrecision(0) << alt << ",6,0,17\r\n";
if (faked_fsdata) {
xfree(fs);
static void
data_write()
{
-
if (waypt_count()) {
- static const char* ozi_wpt_header =
- "OziExplorer Waypoint File Version 1.1\r\n"
- "WGS 84\r\n"
- "Reserved 2\r\n"
- "Reserved 3\r\n";
-
- track_out_count = route_out_count = 0;
+ track_out_count = route_out_count = 0;
ozi_objective = wptdata;
ozi_openfile(ozi_ofname);
- gbfprintf(file_out, ozi_wpt_header);
+ *ozi_file.stream << "OziExplorer Waypoint File Version 1.1\r\n"
+ << "WGS 84\r\n"
+ << "Reserved 2\r\n"
+ << "Reserved 3\r\n";
waypt_disp_all(ozi_waypt_pr);
}
--- /dev/null
+OziExplorer Route File Version 1.0\r
+WGS 84\r
+Reserved 1\r
+Reserved 2\r
+R,1,1 COSTANERO JA,,\r
+W,1,,1,MPCHIC,-34.445850,-58.523720,40507.8513987,0,1,3,0,65535,MARINA PUNTA CHICA,0,0\r
+W,1,,2,JA12,-34.447380,-58.507270,41344.8282040,0,1,3,0,65535,,0,0\r
+R,2,1 PCHI COLONIA,,\r
+W,2,,1,COLONI,-34.467500,-57.854170,,0,1,3,0,65535,07-OCT-00 18:22,0,0\r
+W,2,,2,COLBO3W ,-34.477470,-57.861670,41154.0041088,0,1,3,0,65535,,0,0\r
--- /dev/null
+OziExplorer Track Point File Version 2.1\r
+WGS 84\r
+Altitude is in Feet\r
+Reserved 3\r
+0,2,255,Vézelay / Cuncy-lès-Varzy ,1,0,2,8421376,0\r
+2390\r
+ 47.466222, 3.747318,0, 1258.8,39307.3279977, 13-août-07, 07:52:19\r
+ 47.466150, 3.747233,0, 1236.5,39307.3281134, 13-août-07, 07:52:28\r
+ 47.466130, 3.747113,0, 1243.4,39307.3282292, 13-août-07, 07:52:39\r
+ 47.466078, 3.747023,0, 1237.5,39307.3282986, 13-août-07, 07:52:44\r
+ 47.466020, 3.746888,0, 1221.4,39307.3283681, 13-août-07, 07:52:51\r
+ 47.465943, 3.746815,0, 1203.7,39307.3284259, 13-août-07, 07:52:55\r
+ 47.465872, 3.746727,0, 1177.2,39307.3284954, 13-août-07, 07:53:02\r
+ 47.465902, 3.746598,0, 1168.3,39307.3285532, 13-août-07, 07:53:06\r
+ 47.465900, 3.746465,0, 1159.1,39307.3286343, 13-août-07, 07:53:14\r
+ 47.465792, 3.746433,0, 1157.8,39307.3287037, 13-août-07, 07:53:20\r
+ 47.465713, 3.746388,0, 1154.5,39307.3287616, 13-août-07, 07:53:25\r
+ 47.465695, 3.746242,0, 1160.4,39307.3288426, 13-août-07, 07:53:32\r
+ 47.465697, 3.746097,0, 1160.1,39307.3289236, 13-août-07, 07:53:38\r
+ 47.465717, 3.745948,0, 1169.3,39307.3289815, 13-août-07, 07:53:44\r
+ 47.465715, 3.745807,0, 1189.0,39307.3290625, 13-août-07, 07:53:51\r
+ 47.465640, 3.745703,0, 1205.0,39307.3291551, 13-août-07, 07:53:59\r
+ 47.465575, 3.745608,0, 1203.1,39307.3292130, 13-août-07, 07:54:04\r
+ 47.465488, 3.745547,0, 1197.2,39307.3292708, 13-août-07, 07:54:08\r
+ 47.465447, 3.745437,0, 1180.8,39307.3293519, 13-août-07, 07:54:16\r
+ 47.465353, 3.745390,0, 1157.5,39307.3294213, 13-août-07, 07:54:22\r
+ 47.465298, 3.745282,0, 1141.4,39307.3295139, 13-août-07, 07:54:30\r
+ 47.465250, 3.745155,0, 1100.1,39307.3296181, 13-août-07, 07:54:39\r
+ 47.465157, 3.745133,0, 1101.4,39307.3296759, 13-août-07, 07:54:43\r
+ 47.465018, 3.745113,0, 1094.5,39307.3297569, 13-août-07, 07:54:50\r
+ 47.465010, 3.744965,0, 1101.7,39307.3298148, 13-août-07, 07:54:55\r
+ 47.464992, 3.744823,0, 1114.2,39307.3299074, 13-août-07, 07:55:03\r
+ 47.464955, 3.744658,0, 1124.3,39307.3300000, 13-août-07, 07:55:12\r
+ 47.464885, 3.744563,0, 1130.6,39307.3300810, 13-août-07, 07:55:18\r
+ 47.464778, 3.744497,0, 1117.1,39307.3301505, 13-août-07, 07:55:25\r
+ 47.464710, 3.744412,0, 1109.2,39307.3302083, 13-août-07, 07:55:29\r
+ 47.464635, 3.744317,0, 1110.9,39307.3302778, 13-août-07, 07:55:36\r
+ 47.464547, 3.744233,0, 1109.6,39307.3303472, 13-août-07, 07:55:41\r
+ 47.464475, 3.744142,0, 1112.8,39307.3304282, 13-août-07, 07:55:48\r
+ 47.464405, 3.744057,0, 1101.7,39307.3304861, 13-août-07, 07:55:53\r
+ 47.464342, 3.743965,0, 1098.1,39307.3305440, 13-août-07, 07:55:59\r
+ 47.464313, 3.743808,0, 1094.8,39307.3306366, 13-août-07, 07:56:07\r
+ 47.464233, 3.743725,0, 1077.7,39307.3307292, 13-août-07, 07:56:15\r
+ 47.464173, 3.743628,0, 1066.6,39307.3308102, 13-août-07, 07:56:22\r
+ 47.464102, 3.743548,0, 1064.9,39307.3308912, 13-août-07, 07:56:29\r
+ 47.464015, 3.743477,0, 1049.9,39307.3309491, 13-août-07, 07:56:34\r
+ 47.463935, 3.743393,0, 1045.3,39307.3310301, 13-août-07, 07:56:41\r
+ 47.463860, 3.743303,0, 1063.3,39307.3311343, 13-août-07, 07:56:50\r
+ 47.463847, 3.743163,0, 1062.7,39307.3312037, 13-août-07, 07:56:56\r
+ 47.463833, 3.743018,0, 1072.5,39307.3312731, 13-août-07, 07:57:01\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.0" creator="GPSBabel - http://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
+ <time>1970-01-01T00:00:00Z</time>
+ <bounds minlat="47.463833000" minlon="3.743018000" maxlat="47.466222000" maxlon="3.747318000"/>
+ <trk>
+ <name>Vézelay / Cuncy-lès-Varzy</name>
+ <trkseg>
+ <trkpt lat="47.466222000" lon="3.747318000">
+ <ele>383.682</ele>
+ <time>2007-08-13T07:52:19.328Z</time>
+ </trkpt>
+ <trkpt lat="47.466150000" lon="3.747233000">
+ <ele>376.885</ele>
+ <time>2007-08-13T07:52:28.328Z</time>
+ </trkpt>
+ <trkpt lat="47.466130000" lon="3.747113000">
+ <ele>378.988</ele>
+ <time>2007-08-13T07:52:39.328Z</time>
+ </trkpt>
+ <trkpt lat="47.466078000" lon="3.747023000">
+ <ele>377.190</ele>
+ <time>2007-08-13T07:52:44.328Z</time>
+ </trkpt>
+ <trkpt lat="47.466020000" lon="3.746888000">
+ <ele>372.283</ele>
+ <time>2007-08-13T07:52:51.328Z</time>
+ </trkpt>
+ <trkpt lat="47.465943000" lon="3.746815000">
+ <ele>366.888</ele>
+ <time>2007-08-13T07:52:55.328Z</time>
+ </trkpt>
+ <trkpt lat="47.465872000" lon="3.746727000">
+ <ele>358.811</ele>
+ <time>2007-08-13T07:53:02.328Z</time>
+ </trkpt>
+ <trkpt lat="47.465902000" lon="3.746598000">
+ <ele>356.098</ele>
+ <time>2007-08-13T07:53:06.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465900000" lon="3.746465000">
+ <ele>353.294</ele>
+ <time>2007-08-13T07:53:14.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465792000" lon="3.746433000">
+ <ele>352.897</ele>
+ <time>2007-08-13T07:53:19.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465713000" lon="3.746388000">
+ <ele>351.892</ele>
+ <time>2007-08-13T07:53:25.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465695000" lon="3.746242000">
+ <ele>353.690</ele>
+ <time>2007-08-13T07:53:32.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465697000" lon="3.746097000">
+ <ele>353.598</ele>
+ <time>2007-08-13T07:53:38.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465717000" lon="3.745948000">
+ <ele>356.403</ele>
+ <time>2007-08-13T07:53:44.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465715000" lon="3.745807000">
+ <ele>362.407</ele>
+ <time>2007-08-13T07:53:51.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465640000" lon="3.745703000">
+ <ele>367.284</ele>
+ <time>2007-08-13T07:53:59.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465575000" lon="3.745608000">
+ <ele>366.705</ele>
+ <time>2007-08-13T07:54:04.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465488000" lon="3.745547000">
+ <ele>364.907</ele>
+ <time>2007-08-13T07:54:08.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465447000" lon="3.745437000">
+ <ele>359.908</ele>
+ <time>2007-08-13T07:54:16.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465353000" lon="3.745390000">
+ <ele>352.806</ele>
+ <time>2007-08-13T07:54:22.329Z</time>
+ </trkpt>
+ <trkpt lat="47.465298000" lon="3.745282000">
+ <ele>347.899</ele>
+ <time>2007-08-13T07:54:30.330Z</time>
+ </trkpt>
+ <trkpt lat="47.465250000" lon="3.745155000">
+ <ele>335.310</ele>
+ <time>2007-08-13T07:54:39.330Z</time>
+ </trkpt>
+ <trkpt lat="47.465157000" lon="3.745133000">
+ <ele>335.707</ele>
+ <time>2007-08-13T07:54:43.330Z</time>
+ </trkpt>
+ <trkpt lat="47.465018000" lon="3.745113000">
+ <ele>333.604</ele>
+ <time>2007-08-13T07:54:50.330Z</time>
+ </trkpt>
+ <trkpt lat="47.465010000" lon="3.744965000">
+ <ele>335.798</ele>
+ <time>2007-08-13T07:54:55.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464992000" lon="3.744823000">
+ <ele>339.608</ele>
+ <time>2007-08-13T07:55:03.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464955000" lon="3.744658000">
+ <ele>342.687</ele>
+ <time>2007-08-13T07:55:12.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464885000" lon="3.744563000">
+ <ele>344.607</ele>
+ <time>2007-08-13T07:55:18.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464778000" lon="3.744497000">
+ <ele>340.492</ele>
+ <time>2007-08-13T07:55:25.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464710000" lon="3.744412000">
+ <ele>338.084</ele>
+ <time>2007-08-13T07:55:29.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464635000" lon="3.744317000">
+ <ele>338.602</ele>
+ <time>2007-08-13T07:55:36.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464547000" lon="3.744233000">
+ <ele>338.206</ele>
+ <time>2007-08-13T07:55:41.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464475000" lon="3.744142000">
+ <ele>339.181</ele>
+ <time>2007-08-13T07:55:48.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464405000" lon="3.744057000">
+ <ele>335.798</ele>
+ <time>2007-08-13T07:55:53.330Z</time>
+ </trkpt>
+ <trkpt lat="47.464342000" lon="3.743965000">
+ <ele>334.701</ele>
+ <time>2007-08-13T07:55:59.331Z</time>
+ </trkpt>
+ <trkpt lat="47.464313000" lon="3.743808000">
+ <ele>333.695</ele>
+ <time>2007-08-13T07:56:07.331Z</time>
+ </trkpt>
+ <trkpt lat="47.464233000" lon="3.743725000">
+ <ele>328.483</ele>
+ <time>2007-08-13T07:56:15.331Z</time>
+ </trkpt>
+ <trkpt lat="47.464173000" lon="3.743628000">
+ <ele>325.100</ele>
+ <time>2007-08-13T07:56:22.331Z</time>
+ </trkpt>
+ <trkpt lat="47.464102000" lon="3.743548000">
+ <ele>324.582</ele>
+ <time>2007-08-13T07:56:28.331Z</time>
+ </trkpt>
+ <trkpt lat="47.464015000" lon="3.743477000">
+ <ele>320.010</ele>
+ <time>2007-08-13T07:56:34.331Z</time>
+ </trkpt>
+ <trkpt lat="47.463935000" lon="3.743393000">
+ <ele>318.607</ele>
+ <time>2007-08-13T07:56:41.331Z</time>
+ </trkpt>
+ <trkpt lat="47.463860000" lon="3.743303000">
+ <ele>324.094</ele>
+ <time>2007-08-13T07:56:50.331Z</time>
+ </trkpt>
+ <trkpt lat="47.463847000" lon="3.743163000">
+ <ele>323.911</ele>
+ <time>2007-08-13T07:56:55.331Z</time>
+ </trkpt>
+ <trkpt lat="47.463833000" lon="3.743018000">
+ <ele>326.898</ele>
+ <time>2007-08-13T07:57:01.331Z</time>
+ </trkpt>
+ </trkseg>
+ </trk>
+</gpx>
--- /dev/null
+OziExplorer Track Point File Version 2.1\r
+WGS 84\r
+Altitude is in Feet\r
+Reserved 3\r
+0,2,255,Vézelay / Cuncy-lès-Varzy,0,0,2,8421376\r
+0\r
+47.466222,3.747318,1,1259,39307.3280015,,\r
+47.466150,3.747233,0,1236,39307.3281056,,\r
+47.466130,3.747113,0,1243,39307.3282330,,\r
+47.466078,3.747023,0,1237,39307.3282908,,\r
+47.466020,3.746888,0,1221,39307.3283719,,\r
+47.465943,3.746815,0,1204,39307.3284181,,\r
+47.465872,3.746727,0,1177,39307.3284992,,\r
+47.465902,3.746598,0,1168,39307.3285455,,\r
+47.465900,3.746465,0,1159,39307.3286381,,\r
+47.465792,3.746433,0,1158,39307.3286959,,\r
+47.465713,3.746388,0,1155,39307.3287654,,\r
+47.465695,3.746242,0,1160,39307.3288464,,\r
+47.465697,3.746097,0,1160,39307.3289158,,\r
+47.465717,3.745948,0,1169,39307.3289853,,\r
+47.465715,3.745807,0,1189,39307.3290663,,\r
+47.465640,3.745703,0,1205,39307.3291589,,\r
+47.465575,3.745608,0,1203,39307.3292168,,\r
+47.465488,3.745547,0,1197,39307.3292631,,\r
+47.465447,3.745437,0,1181,39307.3293557,,\r
+47.465353,3.745390,0,1158,39307.3294251,,\r
+47.465298,3.745282,0,1141,39307.3295177,,\r
+47.465250,3.745155,0,1100,39307.3296219,,\r
+47.465157,3.745133,0,1101,39307.3296682,,\r
+47.465018,3.745113,0,1095,39307.3297492,,\r
+47.465010,3.744965,0,1102,39307.3298071,,\r
+47.464992,3.744823,0,1114,39307.3298997,,\r
+47.464955,3.744658,0,1124,39307.3300038,,\r
+47.464885,3.744563,0,1131,39307.3300733,,\r
+47.464778,3.744497,0,1117,39307.3301543,,\r
+47.464710,3.744412,0,1109,39307.3302006,,\r
+47.464635,3.744317,0,1111,39307.3302816,,\r
+47.464547,3.744233,0,1110,39307.3303395,,\r
+47.464475,3.744142,0,1113,39307.3304205,,\r
+47.464405,3.744057,0,1102,39307.3304784,,\r
+47.464342,3.743965,0,1098,39307.3305478,,\r
+47.464313,3.743808,0,1095,39307.3306404,,\r
+47.464233,3.743725,0,1078,39307.3307330,,\r
+47.464173,3.743628,0,1067,39307.3308140,,\r
+47.464102,3.743548,0,1065,39307.3308835,,\r
+47.464015,3.743477,0,1050,39307.3309529,,\r
+47.463935,3.743393,0,1045,39307.3310339,,\r
+47.463860,3.743303,0,1063,39307.3311381,,\r
+47.463847,3.743163,0,1063,39307.3311960,,\r
+47.463833,3.743018,0,1073,39307.3312654,,\r
# Test Ozi routes.
gpsbabel -i ozi -f ${REFERENCE}/route/ozi.rte -o gpx -F ${TMPDIR}/ozi~gpx.gpx
compare ${TMPDIR}/ozi~gpx.gpx ${REFERENCE}/route/
+gpsbabel -i ozi -f ${REFERENCE}/route/ozi.rte -o ozi -F ${TMPDIR}/ozi~rte.rte
+compare ${REFERENCE}/route/ozi~rte.rte ${TMPDIR}/ozi~rte.rte
+
+# Test Ozi tracks.
+gpsbabel -i ozi -f ${REFERENCE}/track/20070813_short.plt -o gpx -F ${TMPDIR}/20070813_short~plt.gpx
+compare ${REFERENCE}/track/20070813_short~plt.gpx ${TMPDIR}/20070813_short~plt.gpx
+gpsbabel -i ozi -f ${REFERENCE}/track/20070813_short.plt -o ozi -F ${TMPDIR}/20070813_short~plt.plt
+compare ${REFERENCE}/track/20070813_short~plt.plt ${TMPDIR}/20070813_short~plt.plt
+
--- /dev/null
+<para>
+This lets you override the default codec of 'windows-1252'. As an
+input option the codec should correspond to the encoding of the input file.
+As an output option it sets the encoding of the output file.
+</para>